/*
 * @Author: song
 * @Description: 触控辅助
 *               (set lastSet)  true false 按下  --- > true true 持续按下 ----- > true true .... ----- > false true 抬起
 * @Date: 2024年04月16日 星期二 17:04:53
 * @Modify:
 */

using System;
using System.Collections.Generic;
using SCore.Util;
using UnityEngine;

namespace SCore.Function.Touch
{
    public class Touch : IComponent, IUpdatable, IDisposable
    {
        private static readonly int DEFAULT_SWIPE_THRESHOLD = 100; //移动多少才算拖拽
        private static readonly float DEFAULT_TAP_THRESHOLD = 0.2f; //按多长时间算点击
        public bool _stopMulEvent; //屏蔽多手指
        private bool _stop; //是否停止触控
        private float _tapThreshold; //按多长时间算点击

        private List<Finger> _sFingers = new List<Finger>();

        public Action<Finger> OnTap; //快速点击抬起回调 
        public Action<Finger> OnMove; //移动中回调
        public Action<Finger> OnSwipe; //长按抬起回调 或者 拖拽抬起回调
        public Action<Finger> OnUp; //抬起回调
        public Action<float> OnPinch; //缩放回调

        public void Init()
        {
            UnityUpdate.Instance.Register(this);
            _tapThreshold = DEFAULT_TAP_THRESHOLD;
        }

        public void Clear()
        {
            UnityUpdate.Instance.UnRegister(this);
        }


        public void SUpdate(float dt)
        {
            if (_stop)
            {
                return;
            }

            //单手指
            BeginFinger();
            CollectFinger();
            EndFinger();
            UpdateEvents();

            //多手指缩放
            UpdateMulFinger();
        }

        private Finger FindFinger(int index)
        {
            foreach (var finger in _sFingers)
            {
                if (finger._index == index)
                {
                    return finger;
                }
            }

            return null;
        }

        private void BeginFinger()
        {
            for (int index = _sFingers.Count - 1; index >= 0; index--)
            {
                var finger = _sFingers[index];
                if (finger.IsUp())
                {
                    _sFingers.RemoveAt(index);
                }
                else
                {
                    finger._lastSet = finger._set;
                    finger._lastScreenPos = finger._screenPos;
                    finger._set = false;
                    finger._tap = false;
                    finger._swipe = false;
                    finger._move = false;
                }
            }
        }

        private void CollectFinger()
        {
            if (Input.touchCount > 0)
            {
                for (int index = 0; index <= Input.touchCount - 1; index++)
                {
                    var touch = Input.GetTouch(index);
                    if (touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Stationary ||
                        touch.phase == TouchPhase.Moved)
                    {
                        AddFinger(index, touch.position);
                    }
                }
            }
            else
            {
                if (Input.GetMouseButton(0))
                {
                    var screen = new Rect(0, 0, Screen.width, Screen.height);
                    var mousePos = Input.mousePosition;
                    Vector2 mp = new Vector2(mousePos.x, mousePos.y);
                    if (screen.Contains(mp))
                    {
                        AddFinger(-1, mp);
                    }
                }
            }
        }

        private void AddFinger(int index, Vector2 position)
        {
            var finger = FindFinger(index);
            if (finger == null)
            {
                finger = new Finger()
                {
                    _index = index,
                    _startScreenPos = position,
                    _lastScreenPos = position,
                    _lastSet = false,
                    _age = 0,
                };
                _sFingers.Add(finger);
            }

            finger._set = true;
            finger._screenPos = position;
            if (!finger._dragging)
            {
                var sqrMagnitude = finger.GetSwipeScreenDelta().sqrMagnitude;
                if (sqrMagnitude >= DEFAULT_SWIPE_THRESHOLD)
                {
                    finger._dragging = true;
                }
            }
        }

        private void EndFinger()
        {
            for (int index = _sFingers.Count - 1; index >= 0; index--)
            {
                var finger = _sFingers[index];
                if (finger.IsUp())
                {
                    if (finger._age <= _tapThreshold && finger._age >= 0 && !finger._dragging)
                    {
                        finger._tap = true;
                    }
                    else
                    {
                        finger._swipe = true;
                    }
                }
                else if (!finger.IsDown())
                {
                    finger._move = true;
                    finger._age += +Time.unscaledDeltaTime;
                }
            }
        }

        private void UpdateEvents()
        {
            if (_sFingers.Count == 1)
            {
                TriggerEvent();
            }
            else
            {
                if (!_stopMulEvent)
                {
                    TriggerEvent();
                }
            }
        }

        private void TriggerEvent()
        {
            foreach (var finger in _sFingers)
            {
                if (finger.IsUp())
                    OnUp?.Invoke(finger);
                if (finger._tap)
                    OnTap?.Invoke(finger);
                if (finger._swipe)
                    OnSwipe?.Invoke(finger);
                if (finger._move)
                    OnMove?.Invoke(finger);
            }
        }


        private void UpdateMulFinger()
        {
            if (_stopMulEvent)
            {
                return;
            }

            if (_sFingers.Count >= 2)
            {
                //计算所有手指中心点
                Vector2 curCenterPos = Vector2.zero;
                Vector2 lastCenterPos = Vector2.zero;
                foreach (var finger in _sFingers)
                {
                    curCenterPos += finger._screenPos;
                    lastCenterPos += finger._lastScreenPos;
                }

                int fingerCount = _sFingers.Count;
                curCenterPos /= fingerCount;
                lastCenterPos /= fingerCount;
                //计算所有手指到中心点的距离
                float curDistance = 0, lastDistance = 0;
                foreach (var finger in _sFingers)
                {
                    curDistance += Vector2.Distance(curCenterPos, finger._screenPos);
                    lastDistance += Vector2.Distance(lastCenterPos, finger._lastScreenPos);
                }

                curDistance /= fingerCount;
                lastDistance /= fingerCount;
                if (lastDistance > 0)
                {
                    var scale = curDistance / lastDistance;
                    if (scale > 0 && scale < 2)
                    {
                        OnPinch?.Invoke(scale - 1.0f);
                    }
                }

                return;
            }


            var scroll = Input.mouseScrollDelta.y;
            if (scroll != 0)
            {
                scroll /= 10;
                OnPinch?.Invoke(scroll);
            }
        }

        //public
        public void Stop()
        {
            if (_stop)
            {
                return;
            }

            _stop = true;
            _sFingers.Clear();
        }

        public void ReTouch()
        {
            if (!_stop)
            {
                return;
            }

            _stop = false;
        }

        public void Dispose()
        {
            Stop();
            OnTap = null;
            OnPinch = null;
            OnSwipe = null;
            OnMove = null;
            OnUp = null;
        }
    }
}